package com.engine.salary.util.excel;

import cn.hutool.core.util.StrUtil;
import com.engine.salary.entity.taxdeclaration.dto.TaxDeclarationLaborListDTO;
import com.engine.salary.util.SalaryDateUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.beans.BeanUtils;

import java.awt.*;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ExcelUtil {

    /**
     * 生成excel
     *
     * @param rowList
     * @return
     */
    public static XSSFWorkbook genWorkbook(List<List<String>> rowList, String sheetName) {
        XSSFWorkbook workbook = new XSSFWorkbook();

        // 设置title样式
        XSSFCellStyle titleCellStyle = workbook.createCellStyle();
        XSSFFont titleFont = workbook.createFont();
        titleFont.setFontName("仿宋");
        titleFont.setFontHeightInPoints((short) 15);
        titleCellStyle.setFont(titleFont);
        titleCellStyle.setAlignment(HorizontalAlignment.CENTER);
        titleCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());//背景色
        titleCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);


        // 设置主体样式
        XSSFCellStyle cellStyle = workbook.createCellStyle();
        XSSFFont font = workbook.createFont();
        font.setFontName("宋体");
        font.setFontHeightInPoints((short) 10);// 设置字体大小
        cellStyle.setFont(font);// 选择需要用到的字体格式
        cellStyle.setWrapText(true);

        XSSFSheet sheet = workbook.createSheet(sheetName);
        //自适应宽度
        sheet.autoSizeColumn(0, true);
        //默认列宽
        sheet.setDefaultColumnWidth(20);
        //默认行高
        sheet.setDefaultRowHeightInPoints(18);

        for (int rowIndex = 0; rowIndex < rowList.size(); rowIndex++) {
            List<String> infoList = rowList.get(rowIndex);
            XSSFRow row = sheet.createRow(rowIndex);
            for (int cellIndex = 0; cellIndex < infoList.size(); cellIndex++) {
                XSSFCell cell = row.createCell(cellIndex);
                cell.setCellType(CellType.STRING);
                if (rowIndex == 0) {
                    cell.setCellStyle(titleCellStyle);
                } else {
                    cell.setCellStyle(cellStyle);
                }
                cell.setCellValue(infoList.get(cellIndex));
//                sheet.setColumnWidth(cellIndex, 35 * 256);
            }
        }
        return workbook;
    }

    // 设置默认舍入位数，可设为null
    public static XSSFWorkbook genWorkbookWithDefaultPattern(List<List<Object>> rowList, String sheetName, Integer defaultPattern) {
        XSSFWorkbook workbook = new XSSFWorkbook();

        // 设置title样式
        XSSFCellStyle titleCellStyle = workbook.createCellStyle();
        XSSFFont titleFont = workbook.createFont();
        titleFont.setFontName("仿宋");
        titleFont.setFontHeightInPoints((short) 15);
        titleCellStyle.setFont(titleFont);
        titleCellStyle.setAlignment(HorizontalAlignment.CENTER);
        titleCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());//背景色
        titleCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);


        // 设置主体样式
        XSSFCellStyle cellStyle = workbook.createCellStyle();
        XSSFFont font = workbook.createFont();
        font.setFontName("宋体");
        font.setFontHeightInPoints((short) 10);// 设置字体大小
        cellStyle.setFont(font);// 选择需要用到的字体格式
        cellStyle.setWrapText(true);

        XSSFSheet sheet = workbook.createSheet(sheetName);
        //自适应宽度
        sheet.autoSizeColumn(0, true);
        //默认列宽
        sheet.setDefaultColumnWidth(20);
        //默认行高
        sheet.setDefaultRowHeightInPoints(18);


        XSSFCellStyle numberCellStyle = null;
        if (defaultPattern != null) {
            XSSFDataFormat df = workbook.createDataFormat();
            String start = "0.";
            if (defaultPattern.equals(0)) {
                start = "0";
            }
            short format = df.getFormat(start + Stream.generate(() -> "0").limit(defaultPattern).collect(Collectors.joining()) + "_ ");
            numberCellStyle = workbook.createCellStyle();
            BeanUtils.copyProperties(cellStyle, numberCellStyle);
            numberCellStyle.setDataFormat(format);
        }

        for (int rowIndex = 0; rowIndex < rowList.size(); rowIndex++) {
            List<Object> infoList = rowList.get(rowIndex);
            XSSFRow row = sheet.createRow(rowIndex);
            for (int cellIndex = 0; cellIndex < infoList.size(); cellIndex++) {
                XSSFCell cell = row.createCell(cellIndex);
                cell.setCellType(CellType.STRING);
                if (rowIndex == 0) {
                    cell.setCellStyle(titleCellStyle);
                } else {
                    cell.setCellStyle(cellStyle);
                }
                Object o = infoList.get(cellIndex);
                if (o instanceof String) {
                    if (StrUtil.isNotBlank(String.valueOf(o))) {
                        cell.setCellType(CellType.STRING);
                        cell.setCellValue(String.valueOf(o));
                    }
                } else if (o instanceof BigDecimal) {
                    cell.setCellType(CellType.NUMERIC);
                    cell.setCellValue(o == null ? 0 : ((BigDecimal) o).doubleValue());
                    if (defaultPattern != null) {
                        cell.setCellStyle(numberCellStyle);
                    }
                } else {
                    cell.setCellType(CellType.STRING);
                    cell.setCellValue(o == null ? "" : o.toString());
                }
//                sheet.setColumnWidth(cellIndex, 35 * 256);
            }
        }
        return workbook;
    }

    public static <T> XSSFWorkbook genWorkbook(String sheetName, List<T> rowList) {
        List<Object> headerList = Lists.newArrayList();
        List<String> dataIndexList = Lists.newArrayList();
        // 解析表头
        ExcelUtil.parseHeader(TaxDeclarationLaborListDTO.class, headerList, dataIndexList);

        List<List<Object>> rows = new ArrayList<>();
        rows.add(headerList);
        for (int i = 0; i < rowList.size(); i++) {
            List<Object> row = Lists.newArrayListWithExpectedSize(dataIndexList.size());
            for (int j = 0; j < dataIndexList.size(); j++) {
                Object value = getValue(rowList.get(i), dataIndexList.get(j));
                row.add(value);
            }
            rows.add(row);
        }
        return genWorkbookV2(rows, sheetName);
    }

    private static <T> Object getValue(T t, String fieldName) {
        Object value = null;
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(t.getClass());
            PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : props) {
                if (fieldName.equals(property.getName())) {
                    Method method = property.getReadMethod();
                    value = method.invoke(t, new Object[]{});
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return value;
    }

    public static XSSFWorkbook genWorkbookV2(List<List<Object>> rowList, String sheetName) {
        XSSFWorkbook workbook = new XSSFWorkbook();

        // 设置title样式
        XSSFCellStyle titleCellStyle = workbook.createCellStyle();
        XSSFFont titleFont = workbook.createFont();
        titleFont.setFontName("仿宋");
        titleFont.setFontHeightInPoints((short) 15);
        titleCellStyle.setFont(titleFont);
        titleCellStyle.setAlignment(HorizontalAlignment.CENTER);
        titleCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());//背景色
        titleCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);


        // 设置主体样式
        XSSFCellStyle cellStyle = workbook.createCellStyle();
        XSSFFont font = workbook.createFont();
        font.setFontName("宋体");
        font.setFontHeightInPoints((short) 10);// 设置字体大小
        cellStyle.setFont(font);// 选择需要用到的字体格式
        cellStyle.setWrapText(true);

        XSSFSheet sheet = workbook.createSheet(sheetName);
        //自适应宽度
        sheet.autoSizeColumn(0, true);
        //默认列宽
        sheet.setDefaultColumnWidth(20);
        //默认行高
        sheet.setDefaultRowHeightInPoints(18);

        for (int rowIndex = 0; rowIndex < rowList.size(); rowIndex++) {
            List<Object> infoList = rowList.get(rowIndex);
            XSSFRow row = sheet.createRow(rowIndex);
            for (int cellIndex = 0; cellIndex < infoList.size(); cellIndex++) {
                XSSFCell cell = row.createCell(cellIndex);
                if (rowIndex == 0) {
                    cell.setCellStyle(titleCellStyle);
                } else {
                    cell.setCellStyle(cellStyle);
                }
                Object o = infoList.get(cellIndex);
                if (o instanceof String) {
                    if (StrUtil.isNotBlank(String.valueOf(o))) {
                        cell.setCellType(CellType.STRING);
                        cell.setCellValue(String.valueOf(o));
                    }
                } else if (o instanceof BigDecimal) {
                    cell.setCellType(CellType.NUMERIC);
                    cell.setCellValue(o == null ? 0 : ((BigDecimal) o).doubleValue());
                } else if (o instanceof Boolean) {
                    cell.setCellType(CellType.BOOLEAN);
                    cell.setCellValue(String.valueOf(o));
                } else if (o instanceof Date) {
                    cell.setCellType(CellType.STRING);
                    cell.setCellValue(SalaryDateUtil.getFormatLocalDate((Date) o));
                } else {
                    cell.setCellType(CellType.STRING);
                    cell.setCellValue(o == null ? "" : o.toString());
                }
            }
        }
        return workbook;
    }

    // 设置默认舍入位数,可传null
    public static XSSFWorkbook genWorkbookV2WithDefaultPattern(List<List<Object>> rowList, String sheetName, Integer defaultPattern) {
        XSSFWorkbook workbook = new XSSFWorkbook();

        // 设置title样式
        XSSFCellStyle titleCellStyle = workbook.createCellStyle();
        XSSFFont titleFont = workbook.createFont();
        titleFont.setFontName("仿宋");
        titleFont.setFontHeightInPoints((short) 15);
        titleCellStyle.setFont(titleFont);
        titleCellStyle.setAlignment(HorizontalAlignment.CENTER);
        titleCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());//背景色
        titleCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);


        // 设置主体样式
        XSSFCellStyle cellStyle = workbook.createCellStyle();
        XSSFFont font = workbook.createFont();
        font.setFontName("宋体");
        font.setFontHeightInPoints((short) 10);// 设置字体大小
        cellStyle.setFont(font);// 选择需要用到的字体格式
        cellStyle.setWrapText(true);

        XSSFSheet sheet = workbook.createSheet(sheetName);
        //自适应宽度
        sheet.autoSizeColumn(0, true);
        //默认列宽
        sheet.setDefaultColumnWidth(20);
        //默认行高
        sheet.setDefaultRowHeightInPoints(18);

        XSSFCellStyle numberCellStyle = null;
        if (defaultPattern != null) {
            XSSFDataFormat df = workbook.createDataFormat();
            String start = "0.";
            if (defaultPattern.equals(0)) {
                start = "0";
            }
            short format = df.getFormat(start + Stream.generate(() -> "0").limit(defaultPattern).collect(Collectors.joining()) + "_ ");
            numberCellStyle = workbook.createCellStyle();
            BeanUtils.copyProperties(cellStyle, numberCellStyle);
            numberCellStyle.setDataFormat(format);
        }

        for (int rowIndex = 0; rowIndex < rowList.size(); rowIndex++) {
            List<Object> infoList = rowList.get(rowIndex);
            XSSFRow row = sheet.createRow(rowIndex);
            for (int cellIndex = 0; cellIndex < infoList.size(); cellIndex++) {
                XSSFCell cell = row.createCell(cellIndex);
                if (rowIndex == 0) {
                    cell.setCellStyle(titleCellStyle);
                } else {
                    cell.setCellStyle(cellStyle);
                }
                Object o = infoList.get(cellIndex);
                if (o instanceof String) {
                    if (StrUtil.isNotBlank(String.valueOf(o))) {
                        cell.setCellType(CellType.STRING);
                        cell.setCellValue(String.valueOf(o));
                    }
                } else if (o instanceof BigDecimal) {
                    cell.setCellType(CellType.NUMERIC);
                    cell.setCellValue(o == null ? 0 : ((BigDecimal) o).doubleValue());
                    if (defaultPattern != null) {
                        cell.setCellStyle(numberCellStyle);
                    }
                } else if (o instanceof Boolean) {
                    cell.setCellType(CellType.BOOLEAN);
                    cell.setCellValue(String.valueOf(o));
                } else if (o instanceof Date) {
                    cell.setCellType(CellType.STRING);
                    cell.setCellValue(SalaryDateUtil.getFormatLocalDate((Date) o));
                } else {
                    cell.setCellType(CellType.STRING);
                    cell.setCellValue(o == null ? "" : o.toString());
                }
            }
        }
        return workbook;
    }


    public static XSSFWorkbook genWorkbookV2(List<List<Object>> rowList, String sheetName, List<ExcelComment> comments) {
        XSSFWorkbook workbook = new XSSFWorkbook();

        // 设置title样式
        XSSFCellStyle titleCellStyle = workbook.createCellStyle();
        XSSFFont titleFont = workbook.createFont();
        titleFont.setFontName("仿宋");
        titleFont.setFontHeightInPoints((short) 15);
        titleCellStyle.setFont(titleFont);
        titleCellStyle.setAlignment(HorizontalAlignment.CENTER);
        titleCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());//背景色
        titleCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);


        // 设置主体样式
        XSSFCellStyle cellStyle = workbook.createCellStyle();
        XSSFFont font = workbook.createFont();
        font.setFontName("宋体");
        font.setFontHeightInPoints((short) 10);// 设置字体大小
        cellStyle.setFont(font);// 选择需要用到的字体格式
        cellStyle.setWrapText(true);

        XSSFSheet sheet = workbook.createSheet(sheetName);
        //自适应宽度
        sheet.autoSizeColumn(0, true);
        //默认列宽
        sheet.setDefaultColumnWidth(20);
        //默认行高
        sheet.setDefaultRowHeightInPoints(18);

        for (int rowIndex = 0; rowIndex < rowList.size(); rowIndex++) {
            List<Object> infoList = rowList.get(rowIndex);
            XSSFRow row = sheet.createRow(rowIndex);
            for (int cellIndex = 0; cellIndex < infoList.size(); cellIndex++) {
                XSSFCell cell = row.createCell(cellIndex);
                if (rowIndex == 0) {
                    cell.setCellStyle(titleCellStyle);
                } else {
                    cell.setCellStyle(cellStyle);
                }
                Object o = infoList.get(cellIndex);
                if (o instanceof String) {
                    if (StrUtil.isNotBlank(String.valueOf(o))) {
                        cell.setCellType(CellType.STRING);
                        cell.setCellValue(String.valueOf(o));
                    }
                } else if (o instanceof Boolean) {
                    cell.setCellType(CellType.BOOLEAN);
                    cell.setCellValue(String.valueOf(o));
                } else if (o instanceof Date) {
                    cell.setCellType(CellType.STRING);
                    cell.setCellValue(SalaryDateUtil.getFormatLocalDate((Date) o));
                } else {
                    cell.setCellType(CellType.STRING);
                    cell.setCellValue(String.valueOf(o));
                }
            }
        }

        if (CollectionUtils.isNotEmpty(comments)) {
            for (ExcelComment c : comments) {
                XSSFDrawing patr = sheet.createDrawingPatriarch();
                XSSFComment cellComment = patr.createCellComment(new XSSFClientAnchor(c.dx1, c.dy1, c.dx2, c.dy2, c.col1, c.row1, c.col2, c.row2));
                cellComment.setString(c.content);
            }
        }
        return workbook;
    }


    public static XSSFWorkbook genWorkbookV2(List<List<Object>> rowList, String sheetName, boolean lastRowRed) {
        XSSFWorkbook workbook = new XSSFWorkbook();

        // 设置title样式
        XSSFCellStyle titleCellStyle = workbook.createCellStyle();
        XSSFFont titleFont = workbook.createFont();
        titleFont.setFontName("仿宋");
        titleFont.setFontHeightInPoints((short) 15);
        titleCellStyle.setFont(titleFont);
        titleCellStyle.setAlignment(HorizontalAlignment.CENTER);
        titleCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());//背景色
        titleCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);


        // 设置主体样式
        XSSFCellStyle cellStyle = workbook.createCellStyle();
        XSSFFont font = workbook.createFont();
        font.setFontName("宋体");
        font.setFontHeightInPoints((short) 10);// 设置字体大小
        cellStyle.setFont(font);// 选择需要用到的字体格式
        cellStyle.setWrapText(true);

        XSSFCellStyle redCellStyle = workbook.createCellStyle();
        XSSFFont redFont = workbook.createFont();
        redFont.setFontName("宋体");
        redFont.setFontHeightInPoints((short) 10);// 设置字体大小
        redFont.setColor(new XSSFColor(new Color(0xFF3333), null));
        redFont.setBold(true);
        redCellStyle.setWrapText(true);
        redCellStyle.setFont(redFont);// 选择需要用到的字体格式

        XSSFSheet sheet = workbook.createSheet(sheetName);
        //自适应宽度
        sheet.autoSizeColumn(0, true);
        //默认列宽
        sheet.setDefaultColumnWidth(20);
        //默认行高
        sheet.setDefaultRowHeightInPoints(18);

        for (int rowIndex = 0; rowIndex < rowList.size(); rowIndex++) {
            List<Object> infoList = rowList.get(rowIndex);
            XSSFRow row = sheet.createRow(rowIndex);
            for (int cellIndex = 0; cellIndex < infoList.size(); cellIndex++) {
                XSSFCell cell = row.createCell(cellIndex);
                if (rowIndex == 0) {
                    cell.setCellStyle(titleCellStyle);
                } else {
                    if (lastRowRed && rowIndex == rowList.size() - 1) {
                        cell.setCellStyle(redCellStyle);
                    } else {
                        cell.setCellStyle(cellStyle);
                    }
                }
                Object o = infoList.get(cellIndex);
                if (o instanceof String) {
                    if (StrUtil.isNotBlank(String.valueOf(o))) {
                        cell.setCellType(CellType.STRING);
                        cell.setCellValue(String.valueOf(o));
                    }
                } else if (o instanceof Boolean) {
                    cell.setCellType(CellType.BOOLEAN);
                    cell.setCellValue(String.valueOf(o));
                } else if (o instanceof Date) {
                    cell.setCellType(CellType.STRING);
                    cell.setCellValue(SalaryDateUtil.getFormatLocalDate((Date) o));
                } else {
                    cell.setCellType(CellType.STRING);
                    cell.setCellValue(o == null ? "" : o.toString());
                }
            }
        }
        return workbook;
    }

    /**
     * 解析表头
     *
     * @param clazz
     * @param headerList
     * @param dataIndexList
     * @param <T>
     */
    public static <T> void parseHeader(Class<T> clazz, List<Object> headerList, List<String> dataIndexList) {
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            if (!declaredField.isAnnotationPresent(ExcelHead.class)) {
                continue;
            }
            ExcelHead annotation = declaredField.getAnnotation(ExcelHead.class);
            headerList.add(SalaryI18nUtil.getI18nLabel(annotation.labelId(), annotation.title()));
            dataIndexList.add(declaredField.getName());
        }
    }
}
